package safeCommitter.test.executor.launcher.socket;

import org.eclipse.ui.PartInitException;

import safeCommitter.core.launcher.socket.SCSocketReader;
import safeCommitter.core.template.Activator;
import safeCommitter.model.TestType;
import safeCommitter.test.executor.launcher.parser.TestResultParser;
import safeCommitter.test.report.SCClazzTestResult;
import safeCommitter.test.report.SCResultRepository;
import safeCommitter.test.report.SCTestResult;
import safeCommitter.utils.SCUtils;

/**
 * 
 * Adds default SC parsing behavior for reading Test results from a socket
 * connection and displaying it on a view.
 * 
 * @author Luiz Henrique Rolim
 * 
 */
public final class SCTestSocketReader extends SCSocketReader {

	private Boolean testsPassing = Boolean.TRUE;

	private final SCResultRepository repository = new SCResultRepository();

	private Boolean firstTime = true;

	private final String SC_VIEW = "SafeCommitter.view1";

	public SCTestSocketReader() throws PartInitException {
		super();
		SCUtils.getPage().showView(SC_VIEW);
	}

	/**
	 * Called when the test Runner is started. Needs to create the view on this
	 * point.
	 * 
	 * @param clazzCount
	 *            the Number of classes on the operation
	 * @param testCount
	 *            the Number of test on the operation
	 */
	private void startTests(final int clazzCount, Integer testCount) {
		Activator.getDefault().fireTestsStarted(clazzCount, testCount);
	}

	/**
	 * Called when there's a need to re-calculate the testCount.This will be
	 * called when there's more than one test Engine configured.
	 * 
	 * @param clazzCount
	 * @param testCount
	 */
	private void updateTestCount(final int clazzCount, Integer testCount) {
		Activator.getDefault().updateTestCount(clazzCount, testCount);
	}

	/*
	 * 
	 * (non-Javadoc)
	 * 
	 * 
	 * @see
	 * safeCommitter.core.launcher.socket.SCSocketReader#parseMessage(java.lang
	 * .String)
	 */
	@Override
	protected void parseMessage(final String line) {
		if (line.startsWith("COUNT")) {
			countMessage(line);
		} else if (line.startsWith(TestType.TESTNG.name())
				|| line.startsWith(TestType.JUNIT.name())) {
			testResult(line);
		} else if (line.startsWith("STATS")) {
			updateStats(line);
		} else if (line.equals("NOTESTS")) {
			testsPassing = Boolean.TRUE;
		} else if ("END".equals(line)) {
			endTests();
		}
	}

	private void updateStats(String line) {
		String[] results = line.split("~");
		Integer successCount = Integer.valueOf(results[1]);
		Integer failCount = Integer.valueOf(results[2]);
		Integer skippCount = Integer.valueOf(results[3]);
		Activator.getDefault().updateStats(successCount, failCount, skippCount);
	}

	private void testResult(final String line) {
		SCTestResult result = TestResultParser.getResult(line);
		String clazzName = result.getClassName();
		String fullName = result.getPath();
		SCClazzTestResult clazzTestResult;
		if (!repository.contains(clazzName)) {
			clazzTestResult = repository.addNewClazz(clazzName, result,
					fullName);
			Activator.getDefault().firenewClazzResult(clazzTestResult);
		} else {
			clazzTestResult = repository.addResult(clazzName, result);
		}
		result.setParent(clazzTestResult);
		testsPassing = testsPassing && result.getPassed();
		updateListeners(result);

	}

	/**
	 * Updates the view informing that a new test was executed.
	 * 
	 */
	private void updateListeners(final SCTestResult result) {
		Activator.getDefault().fireTestResult(result);

	}

	private void endTests() {
		jobDone = Boolean.TRUE;
	}

	/**
	 * Calculates the number of tests being executed.
	 * 
	 * @param line
	 *            the line that contains the number of tests run.
	 */
	private void countMessage(final String line) {
		String[] split = line.split("COUNT~TESTNG~");
		if (split.length == 2) {
			String[] strings = split[1].split("~");
			Integer clazzCount = Integer.valueOf(strings[1]);
			Integer testCount = Integer.valueOf(strings[3]);
			if (firstTime) {
				startTests(clazzCount, testCount);
				firstTime = false;
			} else {
				updateTestCount(clazzCount, testCount);
			}

		}
	}

	@Override
	public Boolean getTestsPassing() {
		return testsPassing;
	}

}
